<html>
    <head>
        <title>插件模块</title>
    </head>
    <body>
        <script>
            // 插件模块  Plugin Modules

                    /*
                            可以将模块作为插件加载.

                            这意味着你可能不会在解决方案中引用模块的程序集，但你可以像任何其他模块一样在应用程序启动中加载该模块。
                    */

                    /*
                        一、基本用法

                                WebApplicationBuilder.AddApplicationAsync<T>()扩展方法可以获得配置插件源的选项。

                                    示例：从文件夹加载插件

                                            await builder.AddApplicationAsync<MyPlugInDemoWebModule>(options =>
                                            {
                                                options.PlugInSources.AddFolder(@"D:\Temp\MyPlugIns");
                                            });

                                        这是典型ASP.NETCore应用程序的Startup类。

                                        PlugInSources.AddFolder获取文件夹路径并在该文件夹中加载程序集（通常是dlls）。

                                就是这么简单。ABP将发现给定文件夹中的模块，想常规模块一样配置和初始化它们。
                    */


                    /*
                        二、 插件源  Plug-In Sources  
                        
                                options.PlugInSources实际上是IPlugInSource实现的列表，AddFolder只是以下表达式的快捷方式：

                                    options.PlugInSources.Add(new FolderPlugInSource(@"D:\Temp\MyPlugIns"));

                                (AddFolder()只查找给定文件夹中的程序集文件，而不查找子文件夹。你可以传递SearchOption.AllDirectories作为第二个参数来递归地从子文件夹中探索插件。)



                                还有两个内置的Plug-In Source实现:

                                        PlugInSources.AddFiles()获取程序集列表（通常是dll）文件。这是使用FilePlugInSource类的快捷方式。

                                        PlugInSources.AddTypes()获取模块类类型列表。如果使用它，你需要自己加载模块的程序集，但它在需要时提供了灵活性。
                                        这是使用TypePlugInSource类的快捷方式。

                                如果需要，你可以创建自己的IPlugInSource实现并像其他实现一样添加到options.PlugInSources。
                    */

                    /*
                        三、创建一个简单的插件

                                在解决方案中创建一个简单的 "类库项目"：

                                你可以在模块中添加需要使用的ABP包。至少，你应该将Volo.Abp.Core包添加到项目中，在要安装包的.csproj文件夹中执行以下命令：

                                                abp add-package Volo.Abp.Core

                                每个模块都必须声明一个派生自AbpModule的类。这里，一个简单的模块类，用于解析服务并在应用程序启动时对其进行初始化：

                                                using Microsoft.Extensions.DependencyInjection;
                                                using Volo.Abp;
                                                using Volo.Abp.Modularity;

                                                namespace MyPlugIn
                                                {
                                                    public class MyPlungInModule : AbpModule
                                                    {
                                                        public override void OnApplicationInitialization(ApplicationInitializationContext context)
                                                        {
                                                            var myService = context.ServiceProvider
                                                                .GetRequiredService<MyService>();
                                                            
                                                            myService.Initialize();
                                                        }
                                                    }
                                                }

                                MyService可以是注册到依赖注入系统的任何类，如下所示：

                                                using Microsoft.Extensions.Logging;
                                                using Volo.Abp.DependencyInjection;

                                                namespace MyPlugIn
                                                {
                                                    public class MyService : ITransientDependency
                                                    {
                                                        private readonly ILogger<MyService> _logger;

                                                        public MyService(ILogger<MyService> logger)
                                                        {
                                                            _logger = logger;
                                                        }

                                                        public void Initialize()
                                                        {
                                                            _logger.LogInformation("MyService has been initialized");
                                                        }
                                                    }
                                                }

                                构建项目，打开构建文件夹，找到MyPlugIn.dll：

                                将MyPlugIn.dll复制到插件文件夹中（D:\Temp\MyPlugIns对于本例）。

                                如果你已经像上面描述的那样配置了主应用程序（请参阅基本用法部分），你应该会在应用程序启动时看到MyService has been initialized日志。
                    */

                    /*
                        四、使用Razor页面创建插件

                                创建带有内部视图的插件需要更多的关注。

                                此示例假设你已使用应用程序启动模板和MVC/Razor Pages UI创建了一个新的Web应用程序。

                                在解决方案中创建一个新的类库项目：

                                编辑.csproj文件内容：

                                                <Project Sdk="Microsoft.NET.Sdk.Web">
                                                    <PropertyGroup>
                                                        <TargetFramework>net5.0</TargetFramework>
                                                        <OutputType>Library</OutputType>
                                                        <IsPackable>true</IsPackable>
                                                    </PropertyGroup>

                                                    <ItemGroup>
                                                    <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="4.0.1" />
                                                    </ItemGroup>
                                                </Project>

                                        将Sdk更改为Microsoft.NET.Sdk.Web。

                                        添加了OutputType和IsPackable属性。

                                        添加了Volo.Abp.AspNetCore.Mvc.UI.Theme.SharedNuGet包。
                                        
                                        备注:

                                            根据Volo.Abp.AspNetCore.Mvc.UI.Thame.Shared包是不需要的。

                                            你可以引用更基本的包，如Volo.Abp.AspNetCore.Mvc。

                                            但是，如果你将构建一个UI页面/组件，建议引用Volo.Abp.AspNetCore.Mvc.UI.Thame.Shared包，因为它是最高级的包，不依赖于特定的主题。

                                            如果依赖于特定主题没有问题，你可以直接引用主题的包，以便能够在插件中使用特定于主题的功能。

                                    然后在插件中创建你的模块类：

                                                using System.IO;
                                                using System.Reflection;
                                                using Microsoft.AspNetCore.Mvc.ApplicationParts;
                                                using Microsoft.Extensions.DependencyInjection;
                                                using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
                                                using Volo.Abp.Modularity;

                                                namespace MyMvcUIPlugIn
                                                {
                                                    [DependsOn(typeof(AbpAspNetCoreMvcUiThemeSharedModule))]
                                                    public class MyMvcUIPlugInModule : AbpModule
                                                    {
                                                        public override void PreConfigureServices(ServiceConfigurationContext context)
                                                        {
                                                            PreConfigure<IMvcBuilder>(mvcBuilder =>
                                                            {
                                                                //Add plugin assembly
                                                                mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));

                                                                //Add CompiledRazorAssemblyPart if the PlugIn module contains razor views.
                                                                mvcBuilder.PartManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));
                                                            });
                                                        }
                                                    }
                                                }

                                                取决于AbpAspNetCoreMvcUiThemeSharedModule，因为我们添加了相关的NuGet包。

                                                将插件程序集作为AssemblyPart和CompiledRazorAssemblyPart添加到ASP.NETCore MVC的PartManager。
                                                这是ASP.NET核心所必需的。否则，插件内的控制器或视图将无法工作。


                                            你现在可以在Pages文件夹中添加剃刀页面，例如MyPlugInPage.cshtml：
                                                 
                                                    @page
                                                        @model MyMvcUIPlugIn.Pages.MyPlugInPage
                                                        <h1>Welcome to my plug-in page</h1>
                                                        <p>This page is located inside a plug-in module! :)</p>


                                        现在，你可以构建插件项目了。它将产生以下输出：


                                        将MyMvcUIPlugIn.dll复制到插件文件夹中（D:\Temp\MyPlugIns对于本例）。

                                        如果你已经像上面描述的那样配置了主应用程序（请参阅基本用法部分），你应该能够在你的应用程序：
                    */

                    /*
                        五、讨论

                                在现实世界中，你的插件可能有一些外部依赖项。

                                此外，你的应用程序可能被设计为支持插件。

                                所有这些都是你自己的系统需求。ABP所做的只是在应用程序启动时加载模块。你在模块中做什么取决于你。

                                但是，对于一些常见的情况，我们可以提供一些建议。


                                1、库依赖 Library Dependencies

                                        对于包/dll依赖项，你可以将相关的dll复制到插件文件夹中。ABP会自动加载文件夹中的所有程序集，你的插件将按预期工作。

                                2、数据库结构  Database Schema 

                                        如果你的模块使用关系数据库和Entity Framework Core，它将需要在数据库中提供其表。
                                        
                                        有不同的方法可以确保在应用程序使用插件时创建了表。
                                        
                                        一些例子:

                                                ①、插件可以检查数据库表是否存在，并在应用程序启动时创建表，或者如果插件已更新并需要一些模式更改，则迁移它们。
                                                
                                                   你可以使用EF Core的迁移API来做到这一点。

                                                ②、你可以改进DbMigrator应用程序以查找插件的迁移并执行它们。

                                     可能还有其他解决方案。例如，如果你的数据库管理员不允许你在应用程序代码中更改数据库模式，你可能需要手动向数据库管理员发送SQL文件以将其应用于数据库。   
                    */

                    /*
                        六、插件样品

                                们有一个示例，你可以从abp-example存储库下载它  https://github.com/abpframework/abp-samples/tree/master/DocumentationSamples/Plug-In
                    */
        </script>
    </body>
</html>